#include <iostream>
#include <string>
#include <time.h>
#include <unistd.h>
#include <stdarg.h>
#include <mutex>
#include <fstream>

bool g_issave = false;
static const char* filename = "log.txt";
enum Level
{
    INFO = 0,
    WARRNING,
    ERROR,
    FATAL
};


std::string GetLevel(int level)
{
    switch (level)
    {
    case 0:
        return "INFO";
        break;
    case 1: 
        return "WARRNING";
        break;
    case 2:
        return "ERROR";
        break;
    case 3:
        return "FATAL";
        break;
    default:
        return "Unknow";
        break;
    }
}


std::string Gettime()
{
    char buffer[1024];
    
    time_t t = time(nullptr);
    struct tm* tm = localtime(&t);

    snprintf(buffer,sizeof(buffer) - 1,"%d-%d-%d %d:%d:%d",
    tm->tm_year + 1900,
    tm->tm_mon + 1,
    tm->tm_mday,
    tm->tm_hour,
    tm->tm_min,
    tm->tm_sec);

    return buffer;
}

void PrintToFile(std::string msg)
{
    std::fstream f(filename,std::ios::app);
    if(!f.is_open())
    {
        std::cerr << "log.txt open failed!" << std::endl;
        f.close();
    }
    f << msg.c_str();
    f.close();
}

std::string MessageLog(std::string name,int line,int level,bool issave,const char* format,...)
{
    std::string levstr = GetLevel(level);
    std::string timestr = Gettime();
    std::string selfidstr = std::to_string(getpid());

    va_list args;

    va_start(args,format);

    char buffer[1024];
    vsnprintf(buffer,sizeof(buffer),format,args);

    va_end(args);

    std::string message = "[" + timestr + "]" + "[" + levstr + "]" + "[" + selfidstr + "]" + 
             "[" + name + "]" + "[" + std::to_string(line) + "]" + "[" + buffer + "]" + "\n";
    
    std::mutex mutex;
    if(issave == false)
    {
        mutex.lock();
        std::cout << message;
        mutex.unlock();
    }
    else
        PrintToFile(message);
    return message;
}


#define LOG(level,format,...)                                                                       \
do{                                                                                                 \
    MessageLog(__FILE__,__LINE__,level,g_issave,format,##__VA_ARGS__);                              \
}while(0)                                                           

#define EnableCout()   \
do{                    \
    g_issave = false;  \
} while (0)          

#define EnableFile()    \
do{                     \
    g_issave = true;    \
}while(0)               
